<?php

define('DS', '/');

// define namespacer
define('NAMESPACER', "\\");

// define paths
define('MINI', __DIR__);
define('MINI_CORE', MINI.DS.'core');
define('MINI_LIB', MINI.DS.'lib');
define('MINI_SCRIPTS', MINI.DS.'scripts');
define('MINI_TASKS', MINI.DS.'tasks');
define('MINI_TEMPLATES', MINI.DS.'templates');

// set default timezone
date_default_timezone_set('UTC');

spl_autoload_register('mini_autoload');

// define autoload logic
function mini_autoload($class) {

    // validate the class name supplied
    // class names can only contain letters and numbers
    if (preg_match('/[^a-zA-Z0-9]/', $class) > 0) {
        throw new Exception('Invalid Class name [' . $class . ']');
    }

    // convert to underscorelized file name
    $file = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $class)) .'.php';

    // look in core
    if (mini_include($class, MINI_CORE.DS.$file) === true) {
        return;
    }

    // look in lib
    if (mini_include($class, MINI_LIB.DS.$file)) {
        return;
    }

    // are we running under app environment? if not exit from here
    if (!defined('APP')) {
        return;
    }

    // models
    if (mini_include($class, APP_MODELS.DS.$file)) {
        return;
    }

    // call app's app_autoload
    if (function_exists("app_autoload") && app_autoload($class)) {
        return;
    }

    throw new Exception('Failed to load class ['.$class.']');
}

// make sure that the include happens in the global scope
function mini_include($class, $file) { //error_log('including '.$file);
    if (is_file($file) && require_once($file)) {
        $class_file_map = Configuration::get(Constants::CLASS_FILE_MAP, array());
        $class_file_map[$class] = $file;
        Configuration::set(Constants::CLASS_FILE_MAP, $class_file_map);
        return true;
    }

    //throw new Exception("Could not load file '{$file}'");
    return false;
}

// hook up the application exception handler
function mini_exception_handler($exception) {
    Logger::fatal("Uncaught exception: " , $exception->getMessage(), "\n");

    // apply the user defined excetion handler function if it exists
    if (function_exists("app_exception_handler")) {
        app_exception_handler($exception);
    } else {
        Mini::oops(500);
    }
}

set_exception_handler('mini_exception_handler');

function mini_load_plugins($plugins) {
    foreach ($plugins as $plugin) {
        $file = constant('APP_PLUGINS').DS.$plugin.DS.$plugin.'.php';
        if (mini_include(Inflector::camelize($plugin), $file) === false) {
            throw new Exception('Failed to load plugin ['.$plugin.']');
        }
    }
}

class Mini {

    public static function oops($code) {
        if (function_exists("app_oops")) {
            app_oops($code);
        } else {
            Logger::error('encountered error with status ['.$code.']');
            header($_SERVER["SERVER_PROTOCOL"] . ' ' . $code);
            $path = APP.'/public/'.$code.'.html';
            if (file_exists($path)) {
                include($path);
            }
        }
    }

    public static function parse_cli_args($argv) {
        $_ARG = array();

        function merge_global_options($optionName) {
            $globalOptions = array('h' => 'help', 'p' => 'pretend', 's' => 'skip', 'd' => 'dir');
            return isset($globalOptions[$optionName]) ? $globalOptions[$optionName] : $optionName;
        }

        foreach ($argv as $arg) {
            if (ereg('^-+([[a-zA-Z0-9]+)=(.*)$',$arg,$reg)) { // --run=task1,task2,task3, -r=task1,task2,task3
                $_ARG[merge_global_options($reg[1])] = $reg[2];
            } elseif(ereg('^-+([a-zA-Z0-9]+)$',$arg,$reg)) { // -h, --help
                $_ARG[merge_global_options($reg[1])] = true;
            } else {
                $_ARG['input'][]=$arg; // a b c
            }
        }

        return $_ARG;
    }

    // this function uses the CLASS_FILE_MAP from configuration after the file has already been autoloaded.
    // so autoload cannot call this function
    public static function get_class_file_path($class) {
        $class_file_map = Configuration::get(Constants::CLASS_FILE_MAP, array());
        return isset($class_file_map[$class]) ? $class_file_map[$class] : null;
    }
}
